
#include "zen_vap_entity.h"
#include "zen_exception.h"

namespace Zen { namespace Vap {
	Entity::Entity()
	: Node3D()
	{
	}
	
	Color4f RectColorCalc(Color4f c0, Color4f c1, Color4f c2)
	{
		auto m = Color4fLerp(c1, c2, 0.5f);
		return Color4fLerp(c0, m, 2);
	}
	uint32_t RandomColor()
	{
		auto v = (uint32_t)rand();
		return (v<<8) | 0xff;
	}
	void Entity::setMesh(std::shared_ptr<Mesh> mesh)
	{
		m_mesh = mesh;
		m_is_mesh_dirty = true;
	}
	std::shared_ptr<Mesh> Entity::getMesh()
	{
		return m_mesh;
	}
	void Entity::setTexture(SharedTexture texture) {
		m_texture = texture;
	}
	void Entity::draw()
	{
		if(!m_mesh || m_mesh->coords.empty()) return;

//			auto z = getPositionZ() + dz;
//			if((dz < 0 && z < -20) || (dz > 0 && z > -4)) dz = -dz;
//			setPositionZ(z);
			setRotationAngle(getRotationAngle() + ro);

		this->updateMatrix();

		Node3D::draw();

		this->drawR_();
	}

#if ZEN_APP_GLES
	void Entity::drawR_()
	{
		auto s = GL::Render::Get();
		s->cullFace(m_cull_face);
		if(m_texture && m_mesh->tex_coords.size() == m_mesh->coords.size())
		{
			auto pipe = GL::ShaderKitTexture::GetNormal();
			auto kit = pipe;
			kit->active();

			s->bindBuffer(0);
			kit->bindAttCoordWithData(3, GL::eType::Float, false, 0, m_mesh->coords.data());
			kit->bindAttTexCoordWithData(2, GL::eType::Float, 1, 0, m_mesh->tex_coords.data());
			kit->setUniColor(Vec4{m_color.red, m_color.green, m_color.blue, m_color.alpha });
			kit->setUniMat4(getMatrix());
			if(m_texture) kit->setUniSampler(1, m_texture->buffer().getID());
//			if(m_greyfied) kit->setUniGreyFactor(m_grey_factor);

			GL::Render::Get()->drawElements(GL::eVMode::Triangle, m_mesh->indexes.size(), m_mesh->indexes.data());
		}
//		else {
//			auto pipe = MTShaderKitColors::GetNormal();
//			kit->active();
//
//			s->bindBuffer(0);
//			s->setVertexData(kit->a_coord, 3, GL::eType::Float, false, 0, m_mesh->coords.data());
//			s->setVertexData(kit->a_color, 4, GL::eType::Float, true, 0, m_mesh->colors.data());
//			s->setUniform(kit->u_color, m_color.red, m_color.green, m_color.blue, m_color.alpha);
//			s->setUniform(kit->u_transform, getMatrix());
//
//			Render::Get()->drawElements(GL::eVMode::Triangle, m_mesh->indexes.size(), m_mesh->indexes.data());
//		}
	}
#elif ZEN_APP_METAL
	void Entity::drawR_()
	{
		musts(sizeof(VertexDataTexture3D) == sizeof(MTVBufIN_T3D), "");
		if(m_is_mesh_dirty)
		{
			m_is_mesh_dirty = false;

			std::vector<VertexDataTexture3D> buf;
			std::vector<VertexDataColors3D> buf2;
			buf.resize(m_mesh->coords.size());
			buf2.resize(buf.size());

			for(int i = 0; i < buf.size(); ++i)
			{
				auto & v = buf[i];
				v.coord = Vec4Make(m_mesh->coords[i], 1.f);
				v.tex_coord = m_mesh->tex_coords[i];
				auto & vc = buf2[i];
				vc.coord = v.coord;
				vc.color = m_mesh->colors[i];
			}

			mRBuffer.v.updateBuffer((MTVBufIN_T3D*)(void*)buf.data(), buf.size());
			mRBuffer.i.updateIndexBuffer(m_mesh->indexes.data(), m_mesh->indexes.size());
		}

		mRBuffer.u.updateMatrix(this->getMatrix(), getMatrixVersion(), false);

		mRBuffer.u.updateColor(getColor(), 1.f, m_is_color_dirty);

		m_is_color_dirty = false;
		
		auto blends = Helper::Get()->getBlends(eBlend::Normal);
		auto mode = m_mesh->is_strip? eVMode::TriangleStrip : eVMode::Triangle;

		if( m_texture)
		{
			auto pipe = Metal::ShaderKitT3D::GetShared
			(m_is_grey_mode, m_texture->format(), blends);
			kit->renderIndexed(mRBuffer.u, mRBuffer.v, m_texture->buffer(), mode, mRBuffer.i);
		}
		else
		{
			auto pipe = Metal::ShaderKitColors3D::GetShared(m_is_grey_mode, blends);
			kit->renderIndexed(mRBuffer.u, mRBuffer.vc, mode, mRBuffer.i);

		}
	}
#endif
	
	void Ground::draw()
	{
#
	}
}}
